﻿using System;

namespace ArrayStudyApplication
{
    /*
     数组是一个存储相同类型元素的固定大小的顺序集合。数组是用来存储数据的集合，通常认为数组是一个同一类型变量的集合。
     声明数组变量并不是声明 number0、number1、...、number99 一个个单独的变量，而是声明一个就像 numbers 这样的变量，
     然后使用 numbers[0]、numbers[1]、...、numbers[99] 来表示一个个单独的变量。数组中某个指定的元素是通过索引来访问的。
     所有的数组都是由连续的内存位置组成的。最低的地址对应第一个元素，最高的地址对应最后一个元素。
     
     声明数组:
        语法:
            datatype[] arrayName;
        其中,
            datatype 用于指定被存储在数组中的元素的类型
            []指定数组的秩(维度)。秩指定数组的大小
            arrayName 指定数组的名称
        如: double[] balance;
    
     初始化数组:
        声明一个数组不会在内存中初始化数组。当初始化数组变量时,可以赋值给数组。
        数组是一个引用类型，所有需要使用 new 关键字来创建数组的实例。
        如: double[] balance = new double[10]
     赋值给数组
        可以通过使用索引号赋值给一个单独的数组元素
        如: double[] balance = new double[10];double[] balance = 4500.0;
        可以在声明数组的同时给数组赋值
        如: double[] balance = {2340.0, 4523.69; 3421.0};
        可以创建并初始化一个数组
        如: int[] marks = new int[5] {99, 98, 92, 97, 95};
        在上述情况下，可以省略数组的大小
        int[] marks = new int[] {99, 98, 92, 97, 95};
        可以赋值一个数组到另一个目标数组变量中，在这种情况下，目标和源会指向相同的内存地址
        int[] marks = new int[] {99, 98, 92, 97, 95};
        int[] score = marks;
     当创建一个数组时，C# 编译器会根据数组类型隐式初始化每个数组元素为一个默认值。例如，int 数组的所有元素都会被初始化为 0。
     */

    /*
     访问数组元素、
     元素是通过带索引的数组名称来访问的。这是通过把元素的索引放置在数组名称后的方括号中来实现的。
     如: double salary = balance[9]
     */
    class ArrayStudy1
    {
        public static void ArrayStudy()
        {
            int[] n = new int[10];
            int i, j;

            for (i = 0; i < 10; i++)
            {
                n[i] = i + 100;
            }

            for (j = 0; j < 10; j++)
            {
                Console.WriteLine("Element[{0}] = {1}", j, n[j]);
            }
            Console.ReadLine();
        }
    }

    /*
     使用foreach循环
     在前面的实例中，使用一个for循环来访问每个数组元素，但也可使用一个foreach语句来遍历数组
     */
    class ArrayStudy2
    {
        public static void ArrayStudy()
        {
            int[] n = new int[10];

            for (int i = 0; i < 10; i++)
            {
                n[i] = i + 100;
            }

            foreach (int j in n)
            {
                int i = j - 100;
                Console.WriteLine("Element[{0}] = {1}", i, j);
            }
            Console.ReadKey();
        }
    }

    /*
     C# 支持多维数组,多维数组又称为矩形数组
     语法:
        string[,] names;
        int[, ,] m;
     初始化二维数组
     多维数组可以通过在括号内为每行指定值来进行初始化。
     如: int[,] a = new int[3,4]{
          {0, 1, 2, 3},
          {4, 5, 6, 7},
          {8, 9, 10, 11}
         };
     访问二维数组元素
     二维数组中的元素是通过使用下标（即数组的行索引和列索引）来访问的。
     如: int val = a[2,3];
     */
    class ArrayStudy3
    {
        public static void ArrayStudy()
        {
            int[,] a = new int[5, 2] { { 0, 2 }, { 1, 2 }, { 3, 4 }, { 5, 6 }, { 6, 7 } };

            int i, j;

            for (i = 0; i < 5; i++)
            {
                for (j = 0; j < 2; j++)
                {
                    Console.WriteLine($"a[{i},{j}] = {a[i, j]}");
                }
            }
            Console.ReadKey();
        }
    }

    /*
     声明一个带有 int 值的交错数组 scores
     语法:
        int[] scores;
     声明一个数组不会在内存中创建数组
     语法:
        int[][] scores = new int[5][];
        for (int i = 0; i < scores.Length; i++)
        {
            scores[i] = new int[4];
        }
     可以初始化一个交错数组
        int[][] scores = new int[2][]{new int[]{ 92, 93, 94 }, new int[] { 85, 66, 87, 88 }}
     */
    class ArrayStudy4
    {
        public static void ArrayStudy()
        {
            int[][] a = new int[][] { new int[] { 0, 0 }, new int[] { 1, 2 },
            new int[] { 2, 4 }, new int[] { 3, 6 },new int[] { 4, 8 } };

            int i, j;

            for (i = 0; i < 5; i++)
            {
                for (j = 0; j < 2; j++)
                {
                    Console.WriteLine($"a[{i}][{j}] = {a[i][j]}");
                }
            }
            Console.ReadKey();
        }
    }

    /*
     传递数组给函数
     在 C# 中，您可以传递数组作为函数的参数。您可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。
     */
    class ArrayStudy5
    {
        public double getAverage(int[] arr, int size)
        {
            int i;
            double avg;
            int sum = 0;

            for (i = 0; i < size; ++i)
            {
                sum += arr[i];
            }

            avg = (double)sum / size;
            return avg;
        }

        public static void ArrayStudy()
        {
            ArrayStudy5 ay5 = new();
            int[] balance = new int[] { 1000, 2, 3, 17, 50 };
            double avg;

            avg = ay5.getAverage(balance, 5);

            Console.WriteLine("平均值是: {0}", avg);
            Console.ReadKey();
        }
    }

    /*
     有时，当声明一个方法时，您不能确定要传递给函数作为参数的参数数目。
     C# 参数数组解决了这个问题，参数数组通常用于传递未知数量的参数给函数。
     */
    /*
     params 关键字
     在使用数组作为形参时，C# 提供了 params 关键字，使调用数组为形参的方法时，
     既可以传递数组实参，也可以传递一组数组元素。params 的使用格式为：
     语法:
        public 返回类型 方法名称( param 类型名称[] 数组名称 )
     */
    class ArrayStudy6
    {
        public int AddElements(params int[] arr)
        {
            int sum = 0;
            foreach (int i in arr)
            {
                sum += i;
            }
            return sum;
        }

        public static void ArrayStudy()
        {
            ArrayStudy6 ar6 = new();
            int sum = ar6.AddElements(512, 720, 250, 567, 889);
            Console.WriteLine("总和是: {0}", sum);
            Console.ReadKey();
        }
    }

    /*
     Array类
     Array 类是 C# 中所有数组的基类，它是在 System 命名空间中定义。Array 类提供了各种用于数组的属性和方法。
     Array 类的属性:
        IsFixedSize     获取一个值，该值指示数组是否带有固定大小
        IsReadOnly      获取一个值，该值指示数组是否只读
        Length          获取一个32位整数，该值表示所有维度的数组中的元素总数
        LongLength      获取一个64位整数，该值表示所有维度的数组中的元素总数 
        Rank            获取数组的秩(维度)

     Array 类的方法
     Clear                      根据元素的类型，设置数组中某个范围的元素位零，为false或者为null
     Copy(Array, Array, Int32)  从数组的第一个元素开始复制某个范围的元素到另一个数组的第一个元素位置，长度由一个32位整数指定
     CopyTo(Array, Int32)       从当前的一组数组中复制所有的元素到一个指定的一维数组的指定索引位置，索引由一个32位整数指定
     GetLength                  获取一个32位整数，该值表示指定维度的数组中的元素总数
     GetLongLength              获取一个64位整数，该值表示指定维度的数组中的元素总数
     GetLowerBound              获取数组中指定维度的下界
     GetType                    获取当前实例的类型，从对象(object)基础
     GetUpperBound              获取数组中指定维度的上界
     GetValue(Int32)            获取一维数组中指定位置的值，索引从一个32位整数指定
     */
}